package com.ruyuan.rapid.core.helper;

import com.ruyuan.rapid.common.constants.BasicConst;
import com.ruyuan.rapid.common.enums.ResponseCode;
import com.ruyuan.rapid.common.util.TimeUtil;
import com.ruyuan.rapid.core.context.Context;
import com.ruyuan.rapid.core.context.RapidResponse;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;

import java.util.Objects;

/**
 * 响应的辅助类
 * @author mac
 */
public class ResponseHelper {

    public static FullHttpResponse getHttpResponse(ResponseCode responseCode) {
        RapidResponse resRapidResponse = RapidResponse.buildRapidResponse(responseCode);
        DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                HttpResponseStatus.INTERNAL_SERVER_ERROR,
                Unpooled.wrappedBuffer(resRapidResponse.getContent().getBytes()));

        httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON + ";charset=utf-8");
        httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());
        return httpResponse;
    }

    /**
     * 写回响应信息
     * @param rapidContext
     */
    public static void writeResponse(Context rapidContext) {
        // 设置SS
        rapidContext.setSSTime(TimeUtil.currentTimeMillis());

        // 释放请求资源
        rapidContext.releaseRequest();
        // 如果是写回的状态
        if (rapidContext.isWritten()) {
            FullHttpResponse httpResponse = ResponseHelper.getHttpResponse(rapidContext, (RapidResponse) rapidContext.getResponse());
            // 是否是长连接
            if (!rapidContext.isKeepAlive()) {
                // 如果不是长连接, 则返回响应后关闭连接
                ChannelHandlerContext nettyCtx = rapidContext.getNettyCtx();
                nettyCtx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE);
            } else {
                // 长连接
                // 无需关闭连接
                httpResponse.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
                rapidContext.getNettyCtx().writeAndFlush(httpResponse);
            }

            // 设置成写回结束状态
            rapidContext.completed();
        } else if (rapidContext.isCompleted()) {
            rapidContext.invokeCompletedCallback();
        }
    }

    /**
     * 通过上下文对象和RapidResponse对象构建出netty的响应对象
     * @param ctx
     * @param rapidResponse
     * @return
     */
    private static FullHttpResponse getHttpResponse(Context ctx, RapidResponse rapidResponse) {
        ByteBuf content;
        if (Objects.nonNull(rapidResponse.getFutureResponse())) {
            content = Unpooled.wrappedBuffer(rapidResponse.getFutureResponse().getResponseBodyAsByteBuffer());
        } else if (rapidResponse.getContent() != null) {
            content = Unpooled.wrappedBuffer(rapidResponse.getContent().getBytes());
        } else {
            content = Unpooled.wrappedBuffer(BasicConst.BLANK_SEPARATOR_1.getBytes());
        }
        if (Objects.isNull(rapidResponse.getFutureResponse())) {
            DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                    rapidResponse.getHttpResponseStatus(),
                    content);
            httpResponse.headers().add(rapidResponse.getResponseHeaders());
            httpResponse.headers().add(rapidResponse.getExtraResponseHeaders());
            httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());
            return httpResponse;
        } else {
            rapidResponse.getFutureResponse().getHeaders().add(rapidResponse.getExtraResponseHeaders());
            DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                    HttpResponseStatus.valueOf(rapidResponse.getFutureResponse().getStatusCode()),
                    content);
            httpResponse.headers().add(rapidResponse.getFutureResponse().getHeaders());
            return httpResponse;
        }
    }
}
